/**
 * KopsoxApplicationServices
 * Copyright (C) 2010 Free Software Foundation, Inc. <http://fsf.org/>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kopsox.services.ejb;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

/**
 * Locates a Enterprise Bean from an EJB-Container
 * 
 * @author Konrad Renner
 *
 */
public final class EJBLocator {

	/**
	 * Looks for a Bean und returns it
	 * 
	 * @param <T>
	 * @param clazz
	 * @param jndiName
	 * @param contextProperties 
	 * @return T - An Enterprise Bean
	 * @author Konrad Renner
	 */
	public static final <T> T getEnterpriseBean(Class<T> clazz, String jndiName, Properties contextProperties) {
		return clazz.cast(PortableRemoteObject.narrow(getEnterpriseBean(jndiName,contextProperties), clazz));
	}
	
	/**
	 * Looks for a Bean und returns it
	 * 
	 * @param jndiName
	 * @param contextProperties 
	 * @return Object - An Enterprise Bean
	 * @author Konrad Renner
	 */
	public static final Object getEnterpriseBean(String jndiName, Properties contextProperties) {
		Context context = null;
		
		try {
			if(contextProperties == null) {
				context = new InitialContext();
			}else {
				context = new InitialContext(contextProperties);
			}
			return context.lookup(jndiName);
		}catch(NamingException e) {
			throw new IllegalStateException("Cannot create InitalContext or find "+jndiName,e);
		}finally {
			if(context != null) {
				try {
					context.close();
				}catch(NamingException e) {
					throw new IllegalStateException("Cannot close Context",e);
				}
			}
		}
	}
	
	/**
	 * This builder creates an JNDI-Name of a bean.
	 * NOTE: This class creates an global JNDI name as introduced in EJB 3.1 specification.
	 * 
	 * @author Konrad Renner
	 */
	public static class JNDIName{
		public static final String PREFIX = "java:global";
		public static final char SEPERATOR = '/';
		
		private final StringBuilder builder;
		private final String moduleName;
		private String appName;
		private String beanName;
		private String businessInterface;
		private Properties contextProperties;
		
		/**
		 * The module name of the bean (the name of the EJB JAR or WAR archive) is mandatory
		 * 
		 * @param moduleName
		 */
		public JNDIName(String moduleName) {
			
			if(moduleName == null) {
				throw new NullPointerException("Module name of bean is null");
			}
			this.moduleName = moduleName;
			this.builder = new StringBuilder();
			this.builder.append(PREFIX).append(SEPERATOR);
		}
		
		/**
		 * Sets the application name (the name of the EAR) to the JNDI name.
		 * 
		 * @param name
		 * @return JNDIName
		 * @author Konrad Renner
		 */
		public JNDIName applicationName(String name) {
			this.appName = name;
			return this;
		}
		
		public JNDIName beanName(String name) {
			this.beanName = name;
			return this;
		}
		
		public JNDIName beanName(Class<?> name) {
			this.beanName = name.getSimpleName();
			return this;
		}
		
		/**
		 * Sets the properties for the Context (needed if the bean is deployed on an remote server).
		 * 
		 * 
		 * @param props
		 * @return JNDIName
		 * @author rpri182 - RenK
		 */
		public JNDIName contextProperties(Properties props) {
			this.contextProperties = props;
			return this;
		}
		
		public JNDIName businessInterface(Class<?> interfaze) {
			this.businessInterface = interfaze.getName();
			return this;
		}
		
		/**
		 * Builds an JNDI-Name of a bean for an lookup
		 * 
		 * @return String
		 * @author Konrad Renner
		 */
		public String buildJNDIName() {
			if(this.appName != null) {
				this.builder.append(this.appName);
				this.builder.append(SEPERATOR);
			}
			
			this.builder.append(this.moduleName);
			this.builder.append(SEPERATOR);
			this.builder.append(this.beanName);
			
			if(this.businessInterface != null) {
				this.builder.append('#').append(this.businessInterface);
			}
			
			return this.builder.toString();
		}
		
		/**
		 * Locates an bean and returns it
		 * 
		 * @param <T>
		 * @param clazz
		 * @return T - An Enterprise Bean
		 * @author Konrad Renner
		 */
		public <T> T locateBean(Class<T> clazz) {
			return EJBLocator.getEnterpriseBean(clazz,buildJNDIName(),this.contextProperties);
		}
		
		/**
		 * Locates an bean and returns it
		 * 
		 * @return Object
		 * @author Konrad Renner
		 */
		public Object locateBean() {
			return EJBLocator.getEnterpriseBean(buildJNDIName(),this.contextProperties);
		}
	}
}
